package fr.enseirbmatmeca.apms.hibernate.dao.impl;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.exception.DataException;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;

import fr.enseirbmatmeca.apms.hibernate.dao.UserDAO;
import fr.enseirbmatmeca.apms.spring.model.project.Project;
import fr.enseirbmatmeca.apms.spring.model.project.ProjectCollection;
import fr.enseirbmatmeca.apms.spring.model.project.ProjectGroup;
import fr.enseirbmatmeca.apms.spring.model.user.User;
import fr.enseirbmatmeca.apms.spring.security.ProjectRole;

/**
 * Implementation for User DAOs
 * @author bmeurant, coudar
 */
@Repository("userDao")
public class UserDAOImpl implements UserDAO {

	protected static Log logger = LogFactory.getLog(UserDAOImpl.class);

	@Resource(name = "sessionFactory")
	//	@Autowired
	private SessionFactory sessionFactory;

	/**
	 * {@inheritDoc}
	 */
	public boolean checkLogin(String login, String password) {
		if (null == login || null == password) {
			throw new IllegalArgumentException("Login and password are mandatory. Null values are forbidden.");
		}		
		try {
			//			logger.info("Check user with login: "+login+" and password : [PROTECTED]");
			Session session =sessionFactory.getCurrentSession();
			// create a new criteria
			Criteria crit = session.createCriteria(User.class);
			crit.add(Restrictions.ilike("login", login));
			crit.add(Restrictions.eq("password", password));

			User user = (User)crit.uniqueResult();
			return (user != null);
		}
		catch(DataException e) {
			// Critical errors : database unreachable, etc.
			//			logger.error("Exception - DataAccessException occurs : "+e.getMessage()
			//					+" on complete checkLogin().");
			return false;
		}
	}

	public String createUser(User user) {
		if (null == user.getLogin()) {		
			return ("Login is mandatory. Null value is forbidden.");		
		}		
		//			logger.info("create User with login: "+login);		
		Session session =sessionFactory.getCurrentSession();		
		session.persist(user);		
		return "The user "+user.getLogin()+" has been created.";
	}
	
	public User createUser(String login, String password) {
		if (null == login) {
			throw new IllegalArgumentException(
					"Login is mandatory. Null value is forbidden.");
		}
		logger.info("create User with login: " + login);
		User user = new User(login, password);
		Session session = sessionFactory.getCurrentSession();
		session.persist(user);
		return user;
	}

	/**
	 * {@inheritDoc}
	 */
	public boolean saveUser(User user) {

		try {
			logger.info("save User with login: " + user.getLogin());
			Session session = sessionFactory.openSession();
			session.beginTransaction();
			session.save(user);
			session.getTransaction().commit();
			session.close();
			return true;
		} catch (DataAccessException e) {
			// Critical errors : database unreachable, etc.
			logger.error("Exception - DataAccessException occurs : "
					+ e.getMessage() + " on complete getUser().");
			return false;
		}
	}
	


	public List<User> findAll() {
		logger.info(" session  :"+sessionFactory);
		Session session = sessionFactory.getCurrentSession();
		// create a new criteria
		Criteria crit = session.createCriteria(User.class);
		List<User> userDBlist = crit.list();
		return userDBlist;
	}

	/**
	 * {@inheritDoc}
	 */
	public User getUser(String login) {
		if (null == login) {
			throw new IllegalArgumentException("Login is mandatory. Null value is forbidden.");
		}
		try {
			//			logger.info("get User with login: "+login);
			Session session =sessionFactory.getCurrentSession();
			// create a new criteria
			Criteria crit = session.createCriteria(User.class);
			crit.add(Restrictions.eq("login", login));

			User user = (User)crit.uniqueResult();
			return user;
		}
		catch(DataAccessException e) {
			// Critical errors : database unreachable, etc.
			//			logger.error("Exception - DataAccessException occurs : "+e.getMessage()
			//					+" on complete getUser().");
			return null;
		}
	}

	/**
	 * {@inheritDoc}
	 */
	
	public String updateUser(User user) {
		// TODO Auto-generated method stub
		return null;
	}

	public List<ProjectRole> getProjectRoles(User user, Project project) {
		List<ProjectRole> list = new ArrayList<ProjectRole>();
		Session session = sessionFactory.getCurrentSession();
		
		// We search the user in the project group as students
		Criteria crit = session.createCriteria(ProjectGroup.class)
				.createCriteria("students").add( Restrictions.like("login", user.getLogin()) )
				.createCriteria("project").add( Restrictions.like("id", project.getId()) );
		List<ProjectGroup> grpAsStudent = crit.list();
		for(int i = 0; i < grpAsStudent.size(); i++){
			list.add(new ProjectRole(ProjectRole.AUTHORITY_STUDENT,grpAsStudent.get(i).getId(), null));
		}
		
		
		// We search the user in the project group as reporters
		crit = session.createCriteria(ProjectGroup.class)
				.createCriteria("reporters").add( Restrictions.like("login", user.getLogin()) )
				.createCriteria("project").add( Restrictions.like("id", project.getId()));
		List<ProjectGroup> grpAsReporter = crit.list();
		for(int i = 0; i < grpAsReporter.size(); i++){
			list.add(new ProjectRole(ProjectRole.AUTHORITY_REPORTER,grpAsReporter.get(i).getId(), null));
		}
		
		
		// We search the user in the project group as tutors
		crit = session.createCriteria(ProjectCollection.class)
				.createCriteria("tutors").add( Restrictions.like("login", user.getLogin()))
				.createCriteria("project").add( Restrictions.like("id", project.getId()));
		List<ProjectGroup> grpAsTutor = crit.list();
		for(int i = 0; i < grpAsTutor.size(); i++){
			list.add(new ProjectRole(ProjectRole.AUTHORITY_TUTOR, null, grpAsTutor.get(i).getId()));
		}
		return list;
	}

}